home *** CD-ROM | disk | FTP | other *** search
/ CD Actual 9 / CDACTUAL9.iso / share / Dos / VARIOS / pascal / DRIVES.SWG / 0001_Disk free space.pas
Encoding:
Pascal/Delphi Source File  |  1996-02-21  |  26.7 KB  |  711 lines

  1. program FREE;  { show free disk space and other info }
  2. {$M 32000,0,100000}
  3.  
  4.  
  5. {$IFDEF Windows}
  6.   This program is intended for DOS real mode only!
  7. {$ELSE}
  8.   {$IFDEF DPMI}
  9.     Compile for real mode so program does not need RTM.EXE and DPMI16BI.OVL!
  10.   {$ENDIF}
  11. {$ENDIF}
  12.  
  13.    {-------------------------------------------------------------------------}
  14.    {                                                                         }
  15.    {                              FREE.PAS                                   }
  16.    {                              ========                                   }
  17.    {     Display drive information and handle phantom floppy drives so       }
  18.    {     that you don't get the annoying 'insert disk in drive' message.     }
  19.    {     That means when a non-active phantom floppy drive letter is         }
  20.    {     listed on the command line, list it's mapped drive and show the     }
  21.    {     info for the mapped drive, like this:                               }
  22.    {                                                                         }
  23.    {             Free A:   ----------- - same drive as B                     }
  24.    {             Free B:             0 - drive not ready                     }
  25.    {                                                                         }
  26.    {     See the program Usage display (FREE /?) for more information.       }
  27.    {                                                                         }
  28.    {-------------------------------------------------------------------------}
  29.    {           This program uses the Object Professional library by          }
  30.    {                          TurboPower Software.                           }
  31.    {-------------------------------------------------------------------------}
  32.    {   (c) 1995 by Ray Bernard Consulting and Design. All Rights Reserved.   }
  33.    {   Portions (c) 1995 by TurboPower Software. All Rights Reserved.        }
  34.    {-------------------------------------------------------------------------}
  35.  
  36.  
  37.    {-------------------------------------------------------------------------}
  38.    {  ABOUT THIS PROGRAM                                                     }
  39.    {  ==================                                                     }
  40.    {  We developed this program to show drive information because it seemed  }
  41.    {  like we were always adding new drives to our computers, then changing  }
  42.    {  around the drive contents to optimize their usage. Most of the 1 gig   }
  43.    {  drives are partitioned into 4 drives for maximum utilization (to make  }
  44.    {  16K sectors instead of 32K sectors). Whenever we would rearrange       }
  45.    {  drive contents, it was helpful to have a utility that would identify   }
  46.    {  all of a computers local and networked drives, and display the drive   }
  47.    {  volume label and type of drive.                                        }
  48.    {                                                                         }
  49.    {  Now that most of the kinks are worked out of this program, it seemed   }
  50.    {  fitting to upload the source code to TurboPower's BBS and CIS forum,   }
  51.    {  in case others would find it handy.                                    }
  52.    {                                                                         }
  53.    {  This program is provided "AS-IS" without any warranty. Although it is  }
  54.    {  copyrighted, free use may be made of the source code by any registered }
  55.    {  TurboPower software customers. Free use may be made of the compiled    }
  56.    {  version regardless of TurboPower customer status.                      }
  57.    {                                                                         }
  58.    {  -Ray Bernard                                                           }
  59.    {   Ray Bernard Consulting and Design      CIS: [73354,3325]              }
  60.    {   June 17, 995                                                          }
  61.    {-------------------------------------------------------------------------}
  62.  
  63. Uses
  64.   DOS,
  65.   OpDOS,
  66.   OpCrt,
  67.   OpString,
  68.   OpInline;
  69.  
  70.  
  71. type
  72.   TPhantomRec = record
  73.                   DrvLtr,
  74.                   MapDrvLtr : Char;
  75.                 end;
  76.  
  77. var
  78.   DriveList      : String[26];  { drive letters extracted from command line }
  79.   HighDriveSpace,
  80.   LowDriveSpace  : LongInt;     { to hold LOW and HIGH options space values }
  81.   ReportOptions  : Word;        { set per command line options }
  82.   PhantomList    : array['A'..'Z'] of TPhantomRec; { phantom drive global list }
  83.  
  84. const
  85.  { Report Options for ShowFreeSpaceAllDrives }
  86.  
  87.   ShowAtOrAbove   = $00000001;   { /H }
  88.   ShowAtOrBelow   = $00000002;   { /L }
  89.   ShowAndPause    = $00000004;   { /P }
  90.   ShowAllDrives   = $00000008;   { /A }
  91.   ShowSize        = $00000010;   { /C }
  92.   ShowType        = $00000020;   { /T }
  93.   ShowVolumeLabel = $00000040;   { /V }
  94.   ShowFloppies    = $00000080;   { /F }
  95.  
  96.   MsPerSec       = 1000;
  97.   Kbyte          = 1024;
  98.   Megabyte       = 1024*Kbyte;
  99.   Gigabyte       = 1024*Megabyte;
  100.   FreeSpacePad   = 11;   { pad free space number string to 11 spaces }
  101.  
  102.  { global declarations }
  103.   DriveLetterSet     : set of Char = ['A'..'Z'];  { for parameter checking }
  104.   CommandDelimiters  : set of char = ['-','/'];   { for parameter checking }
  105.  
  106.   PauseDelaySecs     : Word = 5;  { default seconds to pause after display }
  107.   Debug              : Boolean = True;
  108.  
  109.   DosVer300 = $0300; {for DOS 3.00}
  110.   DosVer320 = $0314; {for DOS 3.20, $14 = 20}
  111.  
  112. procedure ShowUsageAndHalt;
  113. {-Show the usage information for this program }
  114. begin
  115.   HighVideo;
  116.   Writeln('FREE.EXE - Display drive free space and other information.');
  117.   LowVideo;
  118.   Writeln('(c) 1995 by Ray Bernard Consulting and Design, CompuServe: 73354,3325.');
  119.   Writeln('Portions (c) 1987-1995 by TurboPower Software. All Rights Reserved.');
  120.   Writeln('FREE.EXE is "freeware", distributed "as is" and without warranty.');
  121.   Writeln;
  122.   HighVideo;
  123.   Write('Usage: ');
  124.   LowVideo;
  125.   Writeln('FREE [Drives] [Options]');
  126.   Writeln;
  127.   HighVideo;
  128.   Write('Drives: ');
  129.   LowVideo;
  130.   Writeln('One or more drive letters, with or without spaces');
  131.   Writeln('separating them. If no drives are listed the default drive is assumed.');
  132.   Writeln;
  133.   HighVideo;
  134.   Write('Options: ');
  135.   LowVideo;
  136.   Writeln('One or more options, separated by spaces. You may');
  137.   Writeln('also use the first letter of the option, such as /A for /ALL.');
  138.   Writeln('/ALL       show all drives (A and B)');
  139.   Writeln('/FLOPPY    show all drives including A and B');
  140.   Writeln('/HIGH n    all drives with n or more free space');
  141.   Writeln('/LOW n     all drives with n or less free space');
  142.   Writeln('/PAUSE     pause 5 seconds after display or until key pressed');
  143.   Writeln('/PAUSE n   pause n seconds after the display or until key pressed');
  144.   Writeln('/SIZE      drive size (formatted capacity)');
  145.   Writeln('/TYPE      type of drive');
  146.   Writeln('/VOLUME    show volume label');
  147.   Writeln;
  148.   Write('Press a key to continue . . .');
  149.   if ReadKey <> #0 then
  150.    {do nothing} ;
  151.   ClrScr;
  152.   Writeln('FREE.EXE - Usage information, page 2.');
  153.   Writeln;
  154.   Writeln('High and Low free space amounts can be specified in bytes, kbytes, ');
  155.   Writeln('megabytes or gigabytes using (K, M or G), with or without commas to separate');
  156.   Writeln('thousands. Example: 52,428,800 or 52428800 or 50M for fifty megabytes.');
  157.   Writeln;
  158.   Writeln('EXAMPLE PROGRAM OUTPUT:');
  159.   Writeln;
  160.   Writeln('C:>FREE /f /t /v /s');
  161.   Writeln('Free A:             0 (Size 0.0MB) - drive not ready');
  162.   Writeln('Free B:             0 (Size 0.0MB) - drive not ready');
  163.   Writeln('Free C:    48,283,648 (Size 515MB) - local hard drive  IDE#1_V1');
  164.   Writeln('Free D:    47,218,688 (Size 251MB) - local hard drive  IDE#2_V1');
  165.   Writeln('Free E:   162,906,112 (Size 519MB) - local hard drive  SCSI#1_V1');
  166.   Writeln('Free F:    72,351,744 (Size 257MB) - local hard drive  IDE#1_V3');
  167.   Writeln('Free G:    34,570,240 (Size 257MB) - local hard drive  IDE#1_V4');
  168.   Writeln('Free H:    35,274,752 (Size 251MB) - local hard drive  IDE#2_V2');
  169.   Writeln('Free K:   203,807,616 (Size   2GB) - remote or network drive  AT_SERV_C');
  170.   Writeln('Free O:   ----------- - same drive as B');
  171.   Writeln('Free N:    34,570,240 (Size 257MB) - logical SUBST or ASSIGN on G  IDE#1_V4');
  172.   Writeln('Free R:             0 (Size 127MB) - CD-ROM Drive      MFCDISC');
  173.   Writeln;
  174.   Halt;
  175. end;
  176.  
  177. function IsDriveLocal(Drive : Byte) : Boolean;
  178. { -Returns TRUE if drive is local.
  179.    Drive is the drive number (0 for default, 1 for A:, 2 for B: ...).
  180.    NOTE: If DOS 3 or greater is not loaded, it is assumed that the Drive is
  181.    local (since DOS has no standard way of knowing under DOS 2).
  182.    IsDriveLocal is taken from SHARE.PAS, a unit supplied with TurboPower's
  183.    B-Tree Filer. }
  184. var
  185.   Regs : Registers;
  186. begin
  187.   if OpDos.DosVersion >= DosVer300 then   {DOS 3 or greater required}
  188.     begin  
  189.       with Regs do
  190.         begin
  191.           AX := $4409;
  192.           BL := Drive;
  193.           MsDos(Regs);
  194.           if Odd(Flags) then
  195.             IsDriveLocal := True  {if error, then assume drive is local}
  196.           else
  197.             {the drive is local if bit 12 of DX is clear}
  198.             IsDriveLocal := not FlagIsSet(DX,$1000);
  199.         end;
  200.     end
  201.   else
  202.     IsDriveLocal := True;     {assume it's local for DOS < 3}
  203. end;
  204.  
  205.  
  206. function DrvNumToLtr(DriveNum : Byte) : Char;
  207. {-Return Drive Letter for 1-based Drive Number (A=1, B=2, etc.)}
  208. begin
  209.   DrvNumToLtr := Chr(DriveNum+64);
  210. end;
  211.  
  212. function DrvLtrToNum(DriveLetter : Char) : Byte;
  213. {-Return 1-based Drive Number (A=1, B=2, etc.) for DriveLetter}
  214. begin
  215.   DrvLtrToNum := Ord(Upcase(DriveLetter))-64;
  216. end;
  217.  
  218.  
  219. function IsDrivePhantom(DriveLetter : Char; var MappedTo : Char) : Boolean;
  220. {-Return True if Phantom drive and pass back original drive mapped to. }
  221. { Will recognize floppy drives drives reassigned using DRIVER.SYS.     }
  222. var
  223.   Regs : Registers;
  224.   IsPhantom : Boolean;
  225.   DriveNum : Byte;
  226. begin
  227.   IsPhantom := False;
  228.   DriveNum := DrvLtrToNum(DriveLetter);
  229.   if OpDos.DosVersion > DosVer320 then
  230.     begin  {DOS 3.2 or greater required}
  231.       with Regs do
  232.         begin
  233.           AX := $440E;
  234.           BL := DriveNum;
  235.           MsDos(Regs);
  236.           if Odd(Flags) then
  237.             begin
  238.               IsPhantom := False;  {if error, then assume drive not phantom }
  239.             end
  240.           else
  241.             begin
  242.               if AL = 0 then       {the drive is not phantom drive if AL = 0}
  243.                 IsPhantom := False
  244.               else
  245.                 begin
  246.                   IsPhantom := (AL <> DriveNum);
  247.                   if IsPhantom then
  248.                     MappedTo := DrvNumToLtr(AL);
  249.                 end;
  250.             end;
  251.         end;
  252.     end;
  253.   IsDrivePhantom := IsPhantom;
  254. end; { IsDrivePhantom }
  255.  
  256.  
  257. function IsListedAsPhantom(DriveLetter : Char) : Boolean;
  258. {-Refer to this program's global PhantomList variable }
  259. begin
  260.   IsListedAsPhantom := PhantomList[DriveLetter].DrvLtr = DriveLetter;
  261. end;
  262.  
  263.  
  264. procedure RestoreOutputRedirection;
  265. {-Return Write and Writeln to Standard I/O to allow }
  266. { redirection of program output to file or printer  }
  267. begin
  268.   { undo OpCrt's assignment of Output to CRT }
  269.   Close(Output);
  270.   Assign(Output,'');
  271.   Rewrite(Output);
  272. end;
  273.  
  274.  
  275. function NumFloppies : Byte;
  276. {-Return the number of floppy drives installed per DOS "List of Lists" }
  277. var
  278.   Equipment : Byte;
  279. begin
  280.   Equipment := mem[$0040:$0010];
  281.   if (equipment and $0001) = 1 then
  282.     NumFloppies := ((Equipment shr 6) and $0003)+1
  283.   else
  284.     NumFloppies := 0;
  285. end;
  286.  
  287.  
  288. procedure HaltWithMessage(Message : String);
  289. {-Display Message and halt }
  290. begin
  291.   Writeln(Message);
  292.   Halt;
  293. end;
  294.  
  295.  
  296. function InsertCommas(S : String) : String;
  297. {-Add commas to string for thousands. Work from the end  }
  298. { of the string exit on the first space encountered, to  }
  299. { be able to handle strings like: 'TOTAL: 1,000'.        }
  300. var
  301.   I : Word;
  302.   Len : Word;
  303. begin
  304.   Len := Length(S);
  305.   I := Len;
  306.   while I > 1 do begin
  307.     if (Len+1-I) mod 3 = 0 then
  308.       if S[I-1] = ' ' then
  309.         Break
  310.       else
  311.         insert(',', S, I);
  312.     dec(I);
  313.   end;
  314.   InsertCommas := S;
  315. end;
  316.  
  317.  
  318. procedure GetAndSavePhantomInfo(DriveLetter : Char);
  319. {-If DriveLetter is a Phantom drive, set data in PhantomList }
  320. var
  321.   MapCh : Char;
  322. begin
  323.   if IsDrivePhantom(DriveLetter,MapCh) then
  324.     with PhantomList[DriveLetter] do
  325.       begin
  326.         DrvLtr := DriveLetter;
  327.         MapDrvLtr := MapCh;
  328.       end;
  329. end;
  330.  
  331. function DiskTypeString(DriveLetter : Char) : String;
  332. {-Return the disk class information as a string with leading space & dash. }
  333. { Checks the global variable PhantomList for phantom drive info, and exit  }
  334. { for phantom drive without calling GetDiskClass to avoid disk hit.        }
  335. var
  336.   DiskType   : DiskClass;
  337.   DriveNum   : Byte;
  338.   SubDriveCh : Char;
  339.   DTStr      : String;
  340. begin
  341.   DriveNum := DrvLtrToNum(DriveLetter);
  342.   if IsListedAsPhantom(DriveLetter) then
  343.     begin
  344.       DiskTypeString := ' - same drive as '+PhantomList[DriveLetter].MapDrvLtr;
  345.       Exit;
  346.     end;
  347.   DiskType := GetDiskClass(DriveLetter,SubDriveCh);
  348.   case DiskType of
  349.     Floppy360    : DTStr := ' - 360KB,  5.25" diskette';
  350.     Floppy720    : DTStr := ' - 720KB,  3.50" diskette';
  351.     Floppy12     : DTStr := ' - 1.2MB,  5.25" diskette';
  352.     Floppy144    : DTStr := ' - 1.44MB, 3.50" diskette';
  353.     OtherFloppy  : DTStr := ' - unlised diskette type';
  354.     Bernoulli    : DTStr := ' - Bernouli drive';
  355.     HardDisk     : DTStr := ' - local hard drive';
  356.     RamDisk      : DTStr := ' - RAM drive';
  357.     SubstDrive   : DTStr := ' - logical SUBST or ASSIGN on '+
  358.                                        SubDriveCh;
  359.     UnknownDisk  : DTStr := ' - unlisted disk type';
  360.     InvalidDrive : if not IsDriveLocal(DriveNum) then
  361.                      DTStr := ' - remote or network drive'
  362.                    else
  363.                      DTStr := ' - drive not ready';
  364.     NovellDrive  : DTStr := ' - Novelle network drive';
  365.     CDRomDisk    : DTStr := ' - CD-ROM drive';
  366.   else
  367.     { Trap for GetDiskClass update to include new types}
  368.     { before this routine is revised, and ensure that  }
  369.     { a function result is always assigned.            }
  370.     DTStr := 'unrecognized disk type';
  371.   end; {case}
  372.   DiskTypeString := DTStr;
  373. end;
  374.  
  375.  
  376.  
  377. function DiskCapacity(DriveLetter : char) : longint;
  378. {-Return the disk capacity in number of bytes for the specified drive. }
  379. var
  380.   DriveNum          : byte;
  381.   BytesPerCluster,
  382.   AvailClusters,
  383.   TotalClusters,
  384.   SectorsPerCluster,
  385.   BytesPerSector    : word;
  386.   TotalBytes        : longint;
  387. begin
  388.   DiskCapacity := 0;
  389.   if IsListedAsPhantom(DriveLetter) then
  390.     Exit;
  391.   DriveNum := DrvLtrToNum(DriveLetter);
  392.   if GetDiskInfo(DriveNum,AvailClusters,TotalClusters,
  393.                  BytesPerSector,SectorsPerCluster) then
  394.     begin
  395.       BytesPerCluster := LongInt(SectorsPerCluster) * BytesPerSector;
  396.       DiskCapacity := LongInt(TotalClusters) * BytesPerCluster;
  397.     end;
  398. end; { DiskCapacity }
  399.  
  400.  
  401. function DiskCapacityString(DriveLetter : Char) : String;
  402. {-Return disk capacity info in megabytes or gigabytes formatted with commas }
  403. var
  404.   DiskCap : LongInt;
  405.   TempStr : String;
  406. begin
  407.   DiskCap := DiskCapacity(DriveLetter);
  408.   if DiskCap >= Gigabyte then
  409.     TempStr := Long2Str(DiskCap div Gigabyte)+'GB'
  410.   else
  411.     if DiskCap > 9*Megabyte then
  412.       TempStr := InsertCommas(Long2Str(DiskCap div Megabyte))+'MB'
  413.     else
  414.       TempStr := Long2Str(DiskCap div Megabyte)+'.'+
  415.            copy(Long2Str(DiskCap mod Megabyte),1,1)+'MB';
  416.   DiskCapacityString := TempStr;
  417. end;
  418.  
  419. function AvailableDriveSpace(DriveLetter : char) : longint;
  420. {-Return the number of bytes free on specified drive}
  421. var
  422.   DriveNum            : byte;
  423.   BytesPerCluster,
  424.   AvailClusters,
  425.   TotalClusters,
  426.   SectorsPerCluster,
  427.   BytesPerSector      : word;
  428.   TotalBytes          : longint;
  429. begin
  430.   AvailableDriveSpace := 0;
  431.   if IsListedAsPhantom(DriveLetter) then
  432.     Exit;
  433.   DriveNum := DrvLtrToNum(DriveLetter);
  434.   if GetDiskInfo(DriveNum,AvailClusters,TotalClusters,
  435.                  BytesPerSector,SectorsPerCluster) then
  436.     begin
  437.       BytesPerCluster := LongInt(SectorsPerCluster) * BytesPerSector;
  438.       AvailableDriveSpace := LongInt(AvailClusters) * BytesPerCluster;
  439.     end;
  440. end; { AvailableDriveSpace }
  441.  
  442.  
  443. function DriveInfoString(DriveLetter : Char) : String;
  444. {-Return the formatted drive information for DriveLetter.  }
  445. { Use global variable ReportOptions to determine what data }
  446. { should be inlcuded in returned string. Return a nul      }
  447. { string if the drive's infor should not be displayed      }
  448. { per high or low options.                                 }
  449. var
  450.   N  : Byte;
  451.   InfoStr : String;
  452.   ProcResult : Word;
  453.   VolumeStr : VolumeNameStr;
  454.   FreeSpace : LongInt;
  455.   ShowThisDrive : Boolean;
  456. const
  457.   SpacePadWidth = 13;
  458. begin
  459.   InfoStr := 'Free '+DriveLetter+': ';
  460.   if not IsListedAsPhantom(DriveLetter) then
  461.     begin
  462.       FreeSpace := AvailableDriveSpace(DriveLetter);
  463.       InfoStr := InfoStr +
  464.                   LeftPad(InsertCommas(Long2Str(FreeSpace)),SpacePadWidth);
  465.     end
  466.   else
  467.     begin
  468.       InfoStr := InfoStr + '  -----------';
  469.       FreeSpace := 0;
  470.     end;
  471.   if FlagIsSet(ReportOptions,ShowSize) then
  472.     if not IsListedAsPhantom(DriveLetter) then
  473.       InfoStr := InfoStr + ' (Size '+ DiskCapacityString(DriveLetter) + ')'
  474.     else
  475.       InfoStr := InfoStr + ' (Size -----)';
  476.   if FlagIsSet(ReportOptions,ShowType) then
  477.     InfoStr := InfoStr + DiskTypeString(DriveLetter);
  478.   if FlagIsSet(ReportOptions,ShowVolumeLabel) then
  479.     if not IsListedAsPhantom(DriveLetter) then
  480.       begin
  481.         ProcResult := GetVolumeLabel(DriveLetter,VolumeStr);
  482.         if ProcResult = 0 then
  483.           if Length(VolumeStr) > 0 then
  484.             InfoStr := InfoStr + '  '+VolumeStr
  485.           else
  486.             InfoStr := InfoStr + '  no label';
  487.       end;
  488.  
  489.  { handle high and low disk space options }
  490.   if FlagIsSet(ReportOptions,ShowAtOrAbove) or
  491.      FlagIsSet(ReportOptions,ShowAtOrBelow) then
  492.     begin  { allow both settings combined }
  493.       ShowThisDrive := ( (FlagIsSet(ReportOptions,ShowAtOrAbove) and
  494.                              (FreeSpace >= HighDriveSpace)) or
  495.                          (FlagIsSet(ReportOptions,ShowAtOrBelow) and
  496.                              (FreeSpace <= LowDriveSpace)) );
  497.     end
  498.   else
  499.     ShowThisDrive := True;
  500.   if not ShowThisDrive then
  501.     DriveInfoString := ''
  502.   else
  503.     DriveInfoString := InfoStr;
  504. end;
  505.  
  506.  
  507. procedure DisplayDriveInfoString(DriveLetter : Char);
  508. {-Writeln DriveInfoString's result for DriveLetter if not a nul string }
  509. var
  510.   DisplayStr : String;
  511. begin
  512.   DisplayStr := DriveInfoString(DriveLetter);
  513.   if Length(DisplayStr) > 0 then
  514.     Writeln(DisplayStr);
  515. end;
  516.  
  517. procedure DisplayDrivesInfo;
  518. {-Display the info for all drives in DriveList, checking ReportOptions   }
  519. { for display settings.                                                  }
  520. { Before calling DriveInfoString, make all calls to GetPhantomInfo.      }
  521. { DriveInfoString's call to GetDiskInfo will cause a disk in each drive, }
  522. { making any phantom drive current and thus undetectable by our methods. }
  523. { If a single drive was specified on the command line, and it turns out  }
  524. { to be a phantom drive, show the drive info for the mapped drive, too.  }
  525. var
  526.   N : Byte;
  527. begin
  528.  { build global list of phantom drive maps }
  529.   for N := 1 to Length(DriveList) do
  530.     GetAndSavePhantomInfo(DriveList[N]);
  531.  
  532.  { now get and display drive information }
  533.  if (Length(DriveList) = 1) then
  534.    begin  { hangle single specified phantom drive }
  535.      DisplayDriveInfoString(DriveList[1]);
  536.      if IsListedAsPhantom(DriveList[1]) then
  537.        DisplayDriveInfoString(PhantomList[DriveList[1]].MapDrvLtr);
  538.    end
  539.  else    { show drive info for all listed drives }
  540.   for N := 1 to Length(DriveList) do
  541.     DisplayDriveInfoString(DriveList[N]);
  542.  { pause if option enabled }
  543.   if FlagIsSet(ReportOptions,ShowAndPause) then
  544.     Delay(PauseDelaySecs*MsPerSec);
  545. end;
  546.  
  547.  
  548.  
  549. function AllValidDrivesList : String;
  550. {-Return a string containing drive letters of all valid drives}
  551. var
  552.   DriveLetter : Char;
  553.   TempDrivesList : String;
  554.   FirstDrive : Char;
  555. const
  556.   LastDrive = 'Z';
  557. begin
  558.   TempDrivesList := '';
  559.   if FlagIsSet(ReportOptions,ShowFloppies) then
  560.     FirstDrive := 'A'
  561.   else
  562.     FirstDrive := 'C';
  563.   for DriveLetter := FirstDrive to LastDrive do
  564.     if ValidDrive(DriveLetter) then
  565.       TempDrivesList := TempDrivesList + DriveLetter
  566.     else
  567.   { primary floppies show invalid when last access was via the the Phantom }
  568.   { drive, so check DOS equipment list for floppies by calling NumFloppies }
  569.       if (DriveLetter in ['A','B']) and (NumFloppies > 0) then
  570.         TempDrivesList := TempDrivesList + DriveLetter;
  571.   AllValidDrivesList := TempDrivesList;
  572. end;
  573.  
  574.  
  575. function StripCommas(S : String) : String;
  576. {-Remove any commas from S and return as result }
  577. var
  578.   LenS : Byte absolute S;
  579.   P : Byte;
  580. begin
  581.   for P := LenS downto 1 do
  582.     if S[P] = ',' then
  583.       Delete(S,P,1);
  584.   StripCommas := S;
  585. end;
  586.  
  587. procedure ParseCommandLine;
  588. {-Parse command line to get drive list and options }
  589. { First, check to see if a parameter is a drive letter or list of them.   }
  590. { If so, put the letter or letters in the drive list.                     }
  591. { If not a drive letter, the parameter should be a command option.        }
  592. { Process the command option, or ignore if not a valid option (could be   }
  593. { an option parameter or an invalid option).                              }
  594. var
  595.   ChPos,Count   : Byte;
  596.   TempDelaySecs : Word;
  597.   Param,Param2  : String;
  598.   ParamLen      : Byte absolute Param;
  599.   Param2Len     : Byte absolute Param2;
  600.   HLChar        : Char; { /HIGH, /LOW: K = Kbytes, M = Megabytes, G = Gig }
  601. const
  602.   HLCharSet     : set of Char = ['G','K','M'];
  603. begin
  604.  { initialize variables }
  605.   FillChar(PhantomList, SizeOf(PhantomList), #0);
  606.   ReportOptions := 0;
  607.   HighDriveSpace := 0;
  608.   LowDriveSpace := 0;
  609.   for Count := 1 to ParamCount do
  610.     begin
  611.       Param := StUpCase(ParamStr(Count));
  612.       if Param[1] in DriveLetterSet then
  613.         begin
  614.           for ChPos := 1 to ParamLen do  { for drives listed w/no spacing }
  615.             if Pos(Param[ChPos],DriveList) = 0 then  { correct user error }
  616.               if ValidDrive(Param[ChPos]) then
  617.                 DriveList := DriveList + Param[ChPos]
  618.               else
  619.   { primary floppies show invalid when last access was via the the Phantom }
  620.   { drive, so check DOS equipment list for floppies by calling NumFloppies }
  621.                 if (Param[ChPos] in ['A','B']) and (NumFloppies > 0) then
  622.                   DriveList := DriveList + Param[ChPos];
  623.         end
  624.       else
  625.        { 1st char should be command delimiter }
  626.        { 2nd char should indicate option      }
  627.         if Param[1] in CommandDelimiters then
  628.           begin
  629.             case Param[2] of
  630.               'A' : SetFlag(ReportOptions,ShowAllDrives);
  631.               'F' : SetFlag(ReportOptions,ShowFloppies);
  632.               'H' : begin
  633.                       HLChar := #255;  { to check if set }
  634.                       if ParamCount <= Count then
  635.                         HaltWithMessage('specify drive space with /HIGH option');
  636.                       { check for G, K or M }
  637.                       Param2 := StUpCase(ParamStr(Count+1));
  638.                       if Param2[Param2Len] in HLCharSet then
  639.                         begin
  640.                           HLChar := Param2[Param2Len];
  641.                           Delete(Param2,Param2Len,1);
  642.                         end;
  643.                       { validate free space number }
  644.                       if not Str2Long(StripCommas(Param2),HighDriveSpace) then
  645.                         HaltWithMessage('specify amount of drive space with /HIGH option')
  646.                       else  { handle G, K or M }
  647.                         if HLChar <> #255 then
  648.                           begin
  649.                             case HLChar of
  650.                               'G' : HighDriveSpace := HighDriveSpace * Gigabyte;
  651.                               'K' : HighDriveSpace := HighDriveSpace * Kbyte;
  652.                               'M' : HighDriveSpace := HighDriveSpace * Megabyte;
  653.                             end; {case}
  654.                           end;
  655.                       SetFlag(ReportOptions,ShowAtOrAbove);
  656.                       SetFlag(ReportOptions,ShowAllDrives);
  657.                     end;
  658.               'L' : begin
  659.                       HLChar := #255;  { to check if set }
  660.                       if ParamCount <= Count then
  661.                         HaltWithMessage('specify drive space with /LOW option');
  662.                       { check for G, K or M }
  663.                       Param2 := StUpCase(ParamStr(Count+1));
  664.                       if Param2[Param2Len] in HLCharSet then
  665.                         begin
  666.                           HLChar := Param2[Param2Len];
  667.                           Delete(Param2,Param2Len,1);
  668.                         end;
  669.                       { validate free space number }
  670.                       if not Str2Long(StripCommas(Param2),LowDriveSpace) then
  671.                         HaltWithMessage('specify amount of drive space with /LOW option')
  672.                       else  { handle G, K or M }
  673.                         if HLChar <> #255 then
  674.                           begin
  675.                             case HLChar of
  676.                               'G' : LowDriveSpace := LowDriveSpace * Gigabyte;
  677.                               'K' : LowDriveSpace := LowDriveSpace * Kbyte;
  678.                               'M' : LowDriveSpace := LowDriveSpace * Megabyte;
  679.                             end; {case}
  680.                           end;
  681.                       SetFlag(ReportOptions,ShowAtOrBelow);
  682.                       SetFlag(ReportOptions,ShowAllDrives);
  683.                     end;
  684.               'P' : begin
  685.                       SetFlag(ReportOptions,ShowAndPause);
  686.                       if Count < ParamCount then  { next param could be delay }
  687.                         if Str2Word(ParamStr(Count+1),TempDelaySecs) then
  688.                             PauseDelaySecs := TempDelaySecs;
  689.                     end;
  690.               'S' : SetFlag(ReportOptions,ShowSize);
  691.               'T' : SetFlag(ReportOptions,ShowType);
  692.               'V' : SetFlag(ReportOptions,ShowVolumeLabel);
  693.               '?' : ShowUsageAndHalt;
  694.             end; { case }
  695.           end;  { if Param[1] in CommandDelimiters }
  696.     end; { for Count := 1 to ParamCount }
  697.   if FlagIsSet(ReportOptions,ShowAllDrives) or
  698.      FlagIsSet(ReportOptions,ShowFloppies) then
  699.        DriveList := AllValidDrivesList;
  700. end; { ParseCommandLine }
  701.  
  702.  
  703. begin { FREE }
  704.   RestoreOutputRedirection;
  705.   if ParamCount > 0 then
  706.     ParseCommandLine;
  707.   if Length(DriveList) = 0 then  { if no drives on command line }
  708.     DriveList := DefaultDrive;   { default to current the drive }
  709.   DisplayDrivesInfo;
  710. end. { FREE }
  711.